#include "SemanticNodeProperty.h"

#include "SemanticNodeMethodBody.h"
#include "../errors_warnings.h"

/*

<property_definition>	~	<property_mods> <data_type> <property_name>
<property_mods>	~	<property_mod> <property_mods>
<property_mods>	~
<property_mod>	~	public
<property_mod>	~	protected
<property_mod>	~	private
<property_mod>	~	static
<property_mod>	~	abstract
<property_mod>	~	override
<property_mod>	~	virtual
<property_mod>	~	final
<property_name>	~	NAME <prop_array_defs> <property_body>
<prop_array_defs>	~	<prop_array_def> <prop_array_defs>
<prop_array_defs>	~
<prop_array_def>	~	[ int NAME ]
<property_body>	~	{ <property_read> <property_write> }
<property_body>	~	{ <property_write> <property_read> }
<property_read>	~	read { <method_body> }
<property_read>	~
<property_write>	~	write { <method_body> }
<property_write>	~

*/

SemanticNodeProperty::SemanticNodeProperty(const SyntaxTreeNode *syntaxNode, SemanticNode *parent):SemanticNode(parent), ValueType(getNextUniqueID()){
	modPublic = false;
	modProtected = false;
	modPrivate = false;
	modStatic = false;
	modAbstract = false;
	modOverride = false;
	modVirtual = false;
	modFinal = false;

	readNode = NULL;
	writeNode = NULL;

	addPropertyMods(syntaxNode->Nodes->GetData(0));
	setType(syntaxNode->Nodes->GetData(1), syntaxNode->Nodes->GetData(2)->Nodes->GetData(1)->Nodes->GetCount());
	LexicUnit lu = CompilerData->Units->GetLexicUnit(syntaxNode->Nodes->GetData(2)->Nodes->GetData(0)->LexUnitID);
	name = CompilerData->Units->GetLexicUnitString(&lu);

	//TODO za visedimenzionalne Propertye treba negdje spremiti varijable koje se mijenjaju
	SyntaxTreeNode *syntaxReadNode;
	SyntaxTreeNode *syntaxWriteNode;
	SyntaxTreeNode *propertyBody = syntaxNode->Nodes->GetData(2)->Nodes->GetData(2);

	switch (propertyBody->Production){
	case Gr_PropertyBody__spLCBrac_PropertyRead_PropertyWrite_spRCBrac:
		syntaxReadNode = propertyBody->Nodes->GetData(1);
		syntaxWriteNode = propertyBody->Nodes->GetData(2);
		break;
	case Gr_PropertyBody__spLCBrac_PropertyWrite_PropertyRead_spRCBrac:
		syntaxReadNode = propertyBody->Nodes->GetData(2);
		syntaxWriteNode = propertyBody->Nodes->GetData(1);
		break;
	default: ;// ovo se ne smije dogoditi
	}


	if (syntaxReadNode->Production == Gr_PropertyRead__read_spLCBrac_MethodBody_spRCBrac)
		readNode = new SemanticNodeMethodBody(syntaxReadNode->Nodes->GetData(2), this);

	if (syntaxWriteNode->Production == Gr_PropertyWrite__write_spLCBrac_MethodBody_spRCBrac)
		writeNode = new SemanticNodeMethodBody(syntaxWriteNode->Nodes->GetData(2), this);



}

SemanticNodeProperty::~SemanticNodeProperty(){
	delete readNode;
	readNode = NULL;
	delete writeNode;
	writeNode = NULL;
}

void SemanticNodeProperty::addPropertyMods(const SyntaxTreeNode *propertyMods){
	int check1 = 0; // od public, protected, private se moze pojaviti najvise jedan
	int check2 = 0; // od static, abstract, override, virtual, final se moze pojaviti najvise jedan
	for (int i = 0; i < propertyMods->Nodes->GetCount(); ++i)
	{
		switch(propertyMods->Nodes->GetData(i)->Production){
		case Gr_PropertyMod__public:
			modPublic = true;
			if (check1 > 0){
				LexicUnit lu = CompilerData->Units->GetLexicUnit(propertyMods->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_ACCESS_MODIFIERS);
			}
			check1++;
			break;
		case Gr_PropertyMod__protected:
			modProtected = true;
			if (check1 > 0){
				LexicUnit lu = CompilerData->Units->GetLexicUnit(propertyMods->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_ACCESS_MODIFIERS);
			}
			check1++;
			break;
		case Gr_PropertyMod__private:
			modPrivate = true;
			if (check1 > 0){
				LexicUnit lu = CompilerData->Units->GetLexicUnit(propertyMods->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_ACCESS_MODIFIERS);
			}
			check1++;
			break;
		case Gr_PropertyMod__static:
			modStatic = true;
			if (check2 > 0){
				LexicUnit lu = CompilerData->Units->GetLexicUnit(propertyMods->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_ILLEGAL_MODIFIERS_COMBINATION);
			}
			check2++;
			break;
		case Gr_PropertyMod__abstract:
			modAbstract = true;
			if (check2 > 0){
				LexicUnit lu = CompilerData->Units->GetLexicUnit(propertyMods->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_ILLEGAL_MODIFIERS_COMBINATION);
			}
			check2++;
			break;
		case Gr_PropertyMod__override:
			modOverride = true;
			if (check2 > 0){
				LexicUnit lu = CompilerData->Units->GetLexicUnit(propertyMods->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_ILLEGAL_MODIFIERS_COMBINATION);
			}

			check2++;
			break;
		case Gr_PropertyMod__virtual:
			modVirtual = true;
			if (check2 > 0){
				LexicUnit lu = CompilerData->Units->GetLexicUnit(propertyMods->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_ILLEGAL_MODIFIERS_COMBINATION);
			}
			check2++;
			break;
		case Gr_PropertyMod__final:
			modFinal = true;
			if (check2 > 0){
				LexicUnit lu = CompilerData->Units->GetLexicUnit(propertyMods->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_ILLEGAL_MODIFIERS_COMBINATION);
			}
			check2++;
			break;
		default:
			//ovo se ne smije dogoditi
			cout << "greska u property";
			break;
		}
	}

	if (check2 > 1)
	{} //TODO prijavi pogresku
	if (check1 == 0)
		modPrivate = true; //defaultna vrijednost je private
}
/**
 *  @fn	std::string SemanticNodeProperty::getName(void)
 *
 *  @brief	Gets the name.
 *
 *  @author	Hrvoje Torbasinovic
 *  @date	10/23/2009
 *
 *  @return	The name.
 */
std::string SemanticNodeProperty::getName(void) {
	return name;// name;
}

std::string SemanticNodeProperty::toDebugString(int tab) {
	std::ostringstream res;
	for (int i = 0; i < tab; i++) res << DEBUG_STRING_RAZMAK;
	if (modPrivate) res << "private ";
	if (modProtected) res << "protected ";
	if (modPublic) res << "public ";
	if (modStatic) res << "static ";
	if (modAbstract) res << "abstract ";
	if (modOverride) res << "override ";
	if (modVirtual) res << "virtual ";
	if (modFinal) res << "final ";
	res << this->getTypeDebugString() << " " << name;
	res << std::endl;
	if (readNode != NULL)
	{
		for (int i = 0; i < tab; i++) res << DEBUG_STRING_RAZMAK;
		res << "read: " << endl;
		readNode->toDebugString(tab+1);
	}
	if (writeNode != NULL)
		{
			for (int i = 0; i < tab; i++) res << DEBUG_STRING_RAZMAK;
			res << "write: " << endl;
			writeNode->toDebugString(tab+1);
		}

	return res.str();
}


bool SemanticNodeProperty::getIsPublic()
    {
        return modPublic;
    }

bool SemanticNodeProperty::getIsProtected()
    {
        return modProtected;
    }

bool SemanticNodeProperty::getIsPrivate()
    {
        return modPrivate;
    }

bool SemanticNodeProperty::getIsStatic()
    {
        return modStatic;
    }

bool SemanticNodeProperty::getIsAbstract()
    {
        return modAbstract;
    }

bool SemanticNodeProperty::getIsOverride()
    {
        return modOverride;
    }

bool SemanticNodeProperty::getIsVirtual()
    {
        return modVirtual;
    }

bool SemanticNodeProperty::getIsFinal()
    {
        return modFinal;
    }

SemanticNodeMethodBody *SemanticNodeProperty::getReadNode()
    {
        return readNode;
    }

SemanticNodeMethodBody *SemanticNodeProperty::getWriteNode()
    {
        return writeNode;
    }
